
import java.awt.*;
import java.awt.event.*;

public class IPFrame extends Frame implements MouseListener,
	   MouseMotionListener
{
	private ImageData roiImage;

	// Mouse start/cur drag.
	private int mouseStartX;
	private int mouseStartY;
	private int mouseCurX;
	private int mouseCurY;

	// Coords for ROI rectangle.
	private Rectangle roiRect = new Rectangle();
	private boolean drawingROIRect = false;

	private IPWindow ipWindow;

	// Used for addNotify check.
	boolean fComponentsAdjusted = false;

	//{{DECLARE_CONTROLS
	FileDialog openFileDialog1 = new FileDialog(this);
	FileDialog saveFileDialog1 = new FileDialog(this);
	Label label_title = new Label();
	//}}

	//{{DECLARE_MENUS
	MenuBar mainMenuBar = new MenuBar();
	Menu menu1 = new Menu();
	MenuItem openMenuItem = new MenuItem();
	MenuItem saveMenuItem = new MenuItem();
	MenuItem separatorMenuItem = new MenuItem();
	MenuItem exitMenuItem = new MenuItem();
	Menu menu2 = new Menu();
	MenuItem createMenuItem = new MenuItem();
	Menu menu3 = new Menu();
	MenuItem undoMenuItem = new MenuItem();
	MenuItem thresholdMenuItem = new MenuItem();
	MenuItem contrastMenuItem = new MenuItem();
	MenuItem negativeMenuItem = new MenuItem();
	Menu menu4 = new Menu();
	MenuItem aboutMenuItem = new MenuItem();
	Menu menu5 = new Menu();
	MenuItem dumpImageInfoItem = new MenuItem();
	//}}

	public IPWindow getIPWindow()
	{
		return ipWindow;
	}

	public IPFrame(IPWindow _ipWindow)
	{
		super("ROI region");

		ipWindow = _ipWindow;

		setLayout(null);
		setSize(405,305);
		setVisible(false);

		// Init menu items
		openFileDialog1.setMode(FileDialog.LOAD);
		openFileDialog1.setTitle("Open");
		saveFileDialog1.setMode(FileDialog.LOAD);
		saveFileDialog1.setTitle("Save");
		//$$ openFileDialog1.move(24,312);
		//$$ openFileDialog2.move(40,277);
		setTitle("CS6825 Project 2");

		//// File menu
		menu1.setLabel("File");
		menu1.add(openMenuItem);
		openMenuItem.setLabel("Open...");
		openMenuItem.setShortcut(new MenuShortcut(KeyEvent.VK_O, false));

		menu1.add(saveMenuItem);
		//saveMenuItem.setEnabled(false);
		saveMenuItem.setLabel("Save As...");
		saveMenuItem.setShortcut(new MenuShortcut(KeyEvent.VK_S, false));

		menu1.add(separatorMenuItem);
		separatorMenuItem.setLabel("-");
		menu1.add(exitMenuItem);
		exitMenuItem.setLabel("Exit");
		mainMenuBar.add(menu1);

		//// ROI menu
		menu2.setLabel("ROI");
		menu2.add(createMenuItem);
		createMenuItem.setLabel("Create");
		mainMenuBar.add(menu2);

		//// Process menu
		menu3.setLabel("Process");
		menu3.add(undoMenuItem);
		undoMenuItem.setLabel("Undo");
		menu3.add(thresholdMenuItem);
		thresholdMenuItem.setLabel("Threshold");
		menu3.add(contrastMenuItem);
		contrastMenuItem.setLabel("Contrast Stretch");
		menu3.add(negativeMenuItem);
		negativeMenuItem.setLabel("Image Negative");
		mainMenuBar.add(menu3);

		//// Help menu
		menu4.setLabel("Help");
		menu4.add(aboutMenuItem);
		aboutMenuItem.setLabel("About...");
		mainMenuBar.add(menu4);
		setMenuBar(mainMenuBar);

		//// Debug menu
		menu5.setLabel("Debug");
		menu5.add(dumpImageInfoItem);
		dumpImageInfoItem.setLabel("Dump image info");
		mainMenuBar.add(menu5);
		setMenuBar(mainMenuBar);


		//{{REGISTER_LISTENERS
		SymWindow aSymWindow = new SymWindow();
		this.addWindowListener(aSymWindow);
		SymAction lSymAction = new SymAction();
		openMenuItem.addActionListener(lSymAction);
		exitMenuItem.addActionListener(lSymAction);
		aboutMenuItem.addActionListener(lSymAction);
		saveMenuItem.addActionListener(lSymAction);
		createMenuItem.addActionListener(lSymAction);
		undoMenuItem.addActionListener(lSymAction);
		thresholdMenuItem.addActionListener(lSymAction);
		contrastMenuItem.addActionListener(lSymAction);
		negativeMenuItem.addActionListener(lSymAction);
		dumpImageInfoItem.addActionListener(lSymAction);


		addMouseListener(this);
		addMouseMotionListener(this);
		//}}

	}

	public void update(Graphics g)
	{
		paint(g);
	}

	public void paint(Graphics g)
	{
		Insets insets = getInsets();
		//p("I: " + insets.top + ","+ insets.left + ","
		//		+ insets.bottom + ","+insets.right);
		g.clearRect(0,0, getWidth(), getHeight());

		if (ipWindow.hasActiveImage())
		{
			ipWindow.getActiveImage().paint(g, insets.left, insets.top);

		}
		else
		{
			p.print("no active image to paint");
		}

		if (roiRect.width > 0 && roiRect.height > 0)
		{
			g.drawRect(roiRect.x, roiRect.y,
					roiRect.width, roiRect.height);
		}
	}

	public void addNotify()
	{
		// Record the size of the window prior to calling
		// parents addNotify.
		Dimension d = getSize();
		super.addNotify();

		if (fComponentsAdjusted)
			return;

		// Adjust components according to the insets
		setSize(getInsets().left + getInsets().right + d.width,
				getInsets().top + getInsets().bottom + d.height);
		Component components[] = getComponents();
		for (int i = 0; i < components.length; i++)
		{
			Point p = components[i].getLocation();
			p.translate(getInsets().left, getInsets().top);
			components[i].setLocation(p);
		}
		fComponentsAdjusted = true;
	}

	class SymWindow extends WindowAdapter
	{
		public void windowClosing(WindowEvent event)
		{
			Object object = event.getSource();
			if (object == IPFrame.this)
				IPFrame_WindowClosing(event);
		}
	}

	void IPFrame_WindowClosing(WindowEvent event)
	{
		try
		{
			// QuitDialog Create and show as modal
			(new QuitDialog(this, true)).setVisible(true);
		}
		catch (Exception e)
		{
		}
	}

	/**
	 * This is called by our quit dialog when the user confirmed
	 * to close the window.
	 * We notify the application that this window needs to be
	 * removed.
	 */
	void userConfirmedCloseWindow()
	{
		ipWindow.getImageApp().closeWindow(ipWindow.getWindowId());
	}

	class SymAction implements ActionListener
	{
		public void actionPerformed(ActionEvent event)
		{
			Object object = event.getSource();
			if (object == openMenuItem)
				openMenuItem_ActionPerformed(event);
			else if (object == aboutMenuItem)
				aboutMenuItem_ActionPerformed(event);
			else if (object == exitMenuItem)
				exitMenuItem_ActionPerformed(event);
			else if (object == saveMenuItem)
				saveMenuItem_ActionPerformed(event);
			else if (object == createMenuItem)
				createMenuItem_ActionPerformed(event);
			else if (object == undoMenuItem)
				undoMenuItem_ActionPerformed(event);
			else if (object == thresholdMenuItem)
				thresholdMenuItem_ActionPerformed(event);
			else if (object == contrastMenuItem)
				contrastMenuItem_ActionPerformed(event);
			else if (object == negativeMenuItem)
				negativeMenuItem_ActionPerformed(event);
			else if (object == dumpImageInfoItem)
				dumpImageInfoItem_ActionPerformed(event);
		}
	}

	//Method to open Image, either JPEG or GIF
	//loads image into img class variable and
	//calls method to display the image in a
	//new frame, called frame_image_display.
	void openMenuItem_ActionPerformed(ActionEvent event)
	{
		try
		{
			// OpenFileDialog Create and show as modal
			int defMode = openFileDialog1.getMode();
			String defTitle = openFileDialog1.getTitle();
			String defDirectory = openFileDialog1.getDirectory();
			String defFile = "*.jpg;*.gif";

			openFileDialog1 = new java.awt.FileDialog(this, defTitle, defMode);
			openFileDialog1.setDirectory(defDirectory);
			openFileDialog1.setFile(defFile);
			openFileDialog1.setVisible(true);

			//Print out to console the name of file selected
			String filename = (openFileDialog1.getDirectory()).concat(openFileDialog1.getFile());
			System.out.println("Opening: " + filename);

			ipWindow.loadNewImage(filename);
		}
		catch (Exception e)
		{
			p.print("An exception occured: " + e);
		}
	}

	void aboutMenuItem_ActionPerformed(ActionEvent event)
	{
		try
		{
			// AboutDialog Create and show as modal
			(new AboutDialog(this, true)).setVisible(true);
		}
		catch (Exception e)
		{
		}
	}

	void exitMenuItem_ActionPerformed(ActionEvent event)
	{
		try
		{
			// QuitDialog Create and show as modal
			(new QuitDialog(this, true)).setVisible(true);
		}
		catch (Exception e)
		{
		}
	}

	void saveMenuItem_ActionPerformed(ActionEvent event)
	{
		try
		{
			// OpenFileDialog Create and show as modal
			int defMode = saveFileDialog1.getMode();
			String defTitle = saveFileDialog1.getTitle();
			String defDirectory = saveFileDialog1.getDirectory();
			String defFile = "*.jpg";

			saveFileDialog1 = new java.awt.FileDialog(this,
					defTitle, defMode);
			saveFileDialog1.setDirectory(defDirectory);
			saveFileDialog1.setFile(defFile);
			saveFileDialog1.setVisible(true);

			//Print out to console the name of file selected
			String filename = (saveFileDialog1.getDirectory()).concat(saveFileDialog1.getFile());
			ipWindow.saveActiveImage(filename);
		}
		catch (Exception e)
		{
			p.print("An exception occured: " + e);
		}
	}

	void createMenuItem_ActionPerformed(ActionEvent event)
	{
		Insets insets = getInsets();
		ipWindow.getImageApp().createWindow(
				ipWindow.getActiveImage(),
				roiRect.x - insets.left,
				roiRect.y - insets.top,
				roiRect.width,
				roiRect.height);
	}

	void setAppState(int i)
	{
		System.out.println("Setting to state: " + i);
		appState = i;
	}

	void undoMenuItem_ActionPerformed(ActionEvent event)
	{
		ipWindow.restoreImage();
	}

	void thresholdMenuItem_ActionPerformed(ActionEvent event)
	{
		try
		{
			// ThresholdDialog Create and show as modal
			(new ThresholdDialog(this, true)).setVisible(true);
		}
		catch (Exception e)
		{
		}
	}

	void setThresholdValue(String value)
	{
		int ival = -1;
		try {
			ival = Integer.parseInt(value);
		} catch (NumberFormatException e) {
			p.print("Invalid threshold value.");
			return;
		}

		if (ival >= 0 && ival < 256)
		{
			ipWindow.applyThreshold(ival);
		}
		else
		{
			p.print("Threshold should be in range 0-255.");
		}
	}

	void contrastMenuItem_ActionPerformed(ActionEvent event)
	{
		ipWindow.applyContrastStretch();
	}

	void negativeMenuItem_ActionPerformed(ActionEvent event)
	{
		ipWindow.applyImageNegative();
	}

	void dumpImageInfoItem_ActionPerformed(ActionEvent event)
	{
		int width = ipWindow.getActiveImage().getWidth();
		int height = ipWindow.getActiveImage().getHeight();
		p.print("Image width: " + width +
				" Image height: " + height);
	}


	/**
	 * Mouse events
	 */
	public void mouseClicked(MouseEvent e) { }
	public void mouseEntered(MouseEvent e) { }
	public void mouseExited(MouseEvent e) { }
	public void mouseMoved(MouseEvent e) { }

	public void mousePressed(MouseEvent e)
	{
		p("Mouse pressed: " + e.getX() + ", " + e.getY());
		if (ipWindow.hasActiveImage())
		{
			Insets insets = getInsets();
			mouseStartX = e.getX();
			mouseStartY = e.getY();
			// Check bounds
			if (ipWindow.getActiveImage().isValidCoord(
						mouseStartX - insets.left,
						mouseStartY - insets.top) == false)
			{
				return;
			}
			drawingROIRect = true;
		}
	}

	public void mouseReleased(MouseEvent e)
	{
		p("Mouse released: " + e.getX() + ", " + e.getY());
		if (drawingROIRect == true)
		{
			drawingROIRect = false;
		}
	}

	public void mouseDragged(MouseEvent e)
	{
		p("Dragging: " + e.getX() + ", " + e.getY());
		if (drawingROIRect == true)
		{
			Insets insets = getInsets();
			mouseCurX = e.getX();
			mouseCurY = e.getY();

			// Check bounds.  We have to take insets into consideration.
			// Insets are the borders of the frame, and are
			// included in the coordinate system.
			int imgWidth = ipWindow.getActiveImage().getWidth();
			if (mouseCurX - insets.left >= imgWidth)
			{
				mouseCurX = imgWidth - 1 + insets.left;
			}
			else if (mouseCurX < insets.left)
			{
				mouseCurX = insets.left;
			}

			int imgHeight = ipWindow.getActiveImage().getHeight();
			if (mouseCurY - insets.top >= imgHeight)
			{
				mouseCurY = imgHeight - 1 + insets.top;
			}
			else if (mouseCurY < insets.top)
			{
				mouseCurY = insets.top;
			}

			//// Calculate roi rect based on mouse coords.
			if (mouseCurX > mouseStartX)
			{
				roiRect.x = mouseStartX;
				roiRect.width = mouseCurX - mouseStartX;
			}
			else
			{
				roiRect.x = mouseCurX;
				roiRect.width = mouseStartX - mouseCurX;
			}

			if (mouseCurY > mouseStartY)
			{
				roiRect.y = mouseStartY;
				roiRect.height = mouseCurY - mouseStartY;
			}
			else
			{
				roiRect.y = mouseCurY;
				roiRect.height = mouseStartY - mouseCurY;
			}

			repaint();
		}
	}


	public void p(String s)
	{
		System.out.println(s);
	}
	//
	// TODO: change to enums
	// States:
	// 0: default
	// 1: ROI mode, waiting for click
	// 2: ROI mode, click 1
	private int appState = 0;


	// todo: incorporate this into the file states
	private boolean isFileLoaded = false;

	private int roix1 = 0;
	private int roix2 = 0;
	private int curMousex = 0;
	private int curMousey = 0;

}
